﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Web;
using Sausage.Common;
using Sausage.Web.Code;
using Sausage.Web.DataModel;
using Telerik.Web.Mvc;
using Sausage.Web.Models;

namespace Sausage.Web.Domain
{
	public class ProjectQuantityHelper
	{
		public static GridModel<object> Select(JosnPagingQueryModel query)
		{
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID); 
            
            using (var context = new SausageEntities())
			{
				return
					QueryProjectQuantity(
						context.ProjectQuantity.Where(
							item =>
							organization.Contains(item.OrganizationID) &&
							(item.State == (int)ProjectDataStateEnum.Confirmed)),
                        query, isWithChild);
			}
		}

		public static GridModel<object> SubmitSelect(JosnPagingQueryModel query)
		{
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            
            using (var context = new SausageEntities())
			{
				return
					QueryProjectQuantity(
						context.ProjectQuantity.Where(
							item =>
							organization.Contains(item.OrganizationID) &&
							(item.State == (int)ProjectDataStateEnum.Unsubmit ||
							 item.State == (int)ProjectDataStateEnum.AuditRejected)),
                        query, isWithChild);
			}
		}

		public static GridModel<object> AuditSelect(JosnPagingQueryModel query)
		{
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            
            using (var context = new SausageEntities())
			{
				return
					QueryProjectQuantity(context.ProjectQuantity.Where(item =>
					organization.Contains(item.OrganizationID) &&
					(item.State == (int)ProjectDataStateEnum.Submitted ||
					 item.State == (int)ProjectDataStateEnum.SignRejected))
                    , query, isWithChild);
			}
		}

		public static GridModel<object> SignSelect(JosnPagingQueryModel query)
		{
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            
            using (var context = new SausageEntities())
			{
				return
					QueryProjectQuantity(
						context.ProjectQuantity.Where(
							item =>
							organization.Contains(item.OrganizationID) &&
							(item.State == (int)ProjectDataStateEnum.Audited ||
							 item.State == (int)ProjectDataStateEnum.ConfirmationRejected)),
                        query, isWithChild);
			}
		}

		public static GridModel<object> ConfirmSelect(JosnPagingQueryModel query)
		{
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            
            using (var context = new SausageEntities())
			{
				return
					QueryProjectQuantity(context.ProjectQuantity.Where(item =>
					organization.Contains(item.OrganizationID) && item.State == (int)ProjectDataStateEnum.Signed)
                    , query, isWithChild);
			}
		}

        private static GridModel<object> QueryProjectQuantity(IQueryable<ProjectQuantity> source, JosnPagingQueryModel query, bool isWithChild)
		{
			var result = UIHelper.GetGridModelFromQueryModel<ProjectQuantity>(
				source,
				query.page,
				query.limit,
				GetSortDescriptorFromQueryModel(query.SortModel),
                GetSearchFilterFromQueryModel(query.FilterModel, isWithChild));

			var list = result.Data.Select(item => new
													  {
														  item.QuantityID,
														  item.OrganizationID,
														  Organization = item.Organization.OrganizationName,
														  item.ProjectID,
														  ProjectName = item.Project.ProjectName,
														  ProjectCode = item.Project.ProjectCode,
														  item.ConstructionID,
														  Construction = item.Construction.ConstructionName,
														  item.Quantity,
														  Unit = item.Construction.Unit,
														  item.Price,
														  item.Amount,
														  item.CreateDate,
														  item.Applicant,
														  item.ApplicationDate,
														  item.Auditor,
														  item.AuditedDate,
														  item.Signer,
														  item.SignedDate,
														  item.Approver,
														  item.ApprovedDate,
														  item.State,
														  item.IsDelay,
														  item.Memo,
														  item.Comment
													  }).ToList();

			return new GridModel<object>()
					   {
						   Aggregates = result.Aggregates,
						   Data = list,
						   Total = result.Total
					   };
		}

		public static List<ProjectQuantity> GetProjectQuantityListByDate(DateTime applicationDate)
		{
			using (var context = new SausageEntities())
			{
				return (from item in context.ProjectQuantity.Include("Project").Include("Construction").Include("Organization")
						where item.OrganizationID == Helper.CurrentPrincipal.Organization.OrganizationID
							  && item.ApplicationDate.Year == applicationDate.Year
							  && item.ApplicationDate.Month == applicationDate.Month
							  && item.ApplicationDate.Day == applicationDate.Day
                              orderby item.CreateDate ascending
						select item).ToList();
			}
		}

		public static ProjectQuantity GetProjectQuantityByID(Guid quantityID)
		{
			using (var context = new SausageEntities())
			{
				return context.ProjectQuantity.Include("Project").Include("Construction").Include("Organization").FirstOrDefault(
						item => item.QuantityID == quantityID);
			}
		}

		public static DeleteResult DeleteProjectQuantity(Guid quantityID)
		{
			using (SausageEntities context = new SausageEntities())
			{
				ProjectQuantity entity = context.ProjectQuantity.FirstOrDefault(item => item.QuantityID == quantityID);

				if (null != entity)
				{
					try
					{
						context.ProjectQuantity.DeleteObject(entity);
						context.SaveChanges();
					}
					catch (UpdateException)
					{
						return DeleteResult.UsingError;
					}
					return DeleteResult.Ok;
				}
				return DeleteResult.Ok;
			}
		}

		public static void UpdateProjectQuantity(ProjectQuantityListRow data)
		{
			using (SausageEntities context = new SausageEntities())
			{
				var entity = context.ProjectQuantity.FirstOrDefault(item => item.QuantityID == data.QuantityID);
				if (entity == null)
					return;

				if (entity.State != (int)ProjectDataStateEnum.Unsubmit && entity.State != (int)ProjectDataStateEnum.AuditRejected)
					throw new SausageException(string.Format("项目工程量已经提交，不允许执行编辑操作。"));

				entity.ProjectID = data.ProjectID;
				entity.ConstructionID = data.ConstructionID;
				entity.Quantity = data.Quantity;
				entity.Price = data.Price;
				entity.Amount = data.Price * data.Quantity;
				//entity.ApplicationDate = data.ApplicationDate;
				entity.Applicant = Helper.CurrentPrincipal.User.UserName;
				entity.Memo = data.Memo;

				context.SaveChanges();
			}
		}

		public static void UpdateProjectQuantityState(Guid id, int state)
		{
			using (SausageEntities context = new SausageEntities())
			{
				Project project = context.Project.FirstOrDefault(item => item.ProjectID == id);
				if (null != project)
				{
					project.State = state;
					context.SaveChanges();
				}
			}
		}

		public static void CreateProjectQuantity(ProjectQuantityListRow data)
		{
			using (SausageEntities context = new SausageEntities())
			{
				ProjectQuantity entity = new ProjectQuantity()
				{
					QuantityID = Guid.NewGuid(),
					OrganizationID = Helper.CurrentPrincipal.Organization.OrganizationID,
					ProjectID = data.ProjectID,
					ConstructionID = data.ConstructionID,
					Quantity = data.Quantity,
					Price = data.Price,
					Amount = data.Price * data.Quantity,
					CreateDate = DateTime.Now,
					Applicant = Helper.CurrentPrincipal.User.UserName,
					ApplicationDate = data.ApplicationDate,
					State = (int)ProjectDataStateEnum.Unsubmit,
					IsDelay = Helper.IsDelay(data.ApplicationDate),
					Memo = data.Memo
				};

				context.ProjectQuantity.AddObject(entity);
				context.SaveChanges();
			}
		}

		public static void ExecuteSubmit(Guid[] quantities)
		{
			if (null != quantities && quantities.Length > 0)
			{
				using (var context = new SausageEntities())
				{
					var list = context.ProjectQuantity.Where(item => quantities.Contains(item.QuantityID)).ToList();

					foreach (var entity in list)
					{
						entity.State = (int)ProjectDataStateEnum.Submitted;
					}
					context.SaveChanges();
				}
			}
		}

		public static void ExecuteAudit(Guid[] quantities, bool passed, string comment)
		{
			if (null != quantities && quantities.Length > 0)
			{
				using (var context = new SausageEntities())
				{
					var list = context.ProjectQuantity.Where(item => quantities.Contains(item.QuantityID)).ToList();

					foreach (var projectQuantity in list)
					{
						projectQuantity.Auditor = Helper.CurrentPrincipal.User.UserName;
						projectQuantity.AuditedDate = DateTime.Now;
						projectQuantity.Comment = comment;
						projectQuantity.State = passed
													 ? (int)ProjectDataStateEnum.Audited
													 : (int)ProjectDataStateEnum.AuditRejected;
					}
					context.SaveChanges();
				}
			}
		}

		public static void ExecuteConfirm(Guid[] quantities, bool passed, string comment)
		{
			if (null != quantities && quantities.Length > 0)
			{
				using (var context = new SausageEntities())
				{
					var list = context.ProjectQuantity.Where(item => quantities.Contains(item.QuantityID)).ToList();

					foreach (var projectQuantity in list)
					{
						projectQuantity.Approver = Helper.CurrentPrincipal.User.UserName;
						projectQuantity.ApprovedDate = DateTime.Now;
						projectQuantity.Comment = comment;
						projectQuantity.State = passed
													 ? (int)ProjectDataStateEnum.Confirmed
													 : (int)ProjectDataStateEnum.ConfirmationRejected;
					}
					context.SaveChanges();
				}
			}
		}

        private static List<IFilterDescriptor> GetSearchFilterFromQueryModel(IEnumerable<JosnQueryFilterModel> filterModels, bool isWithChild)
		{
			var filterList = new List<IFilterDescriptor>();
			foreach (var item in filterModels)
			{
				if (string.IsNullOrEmpty(item.value))
					continue;

                if (item.property == "OrganizationID" && isWithChild)
                    continue;

				if (item.property.EndsWith("ID", StringComparison.InvariantCultureIgnoreCase))
				{
					var targetID = Guid.Parse(item.value);
					if (targetID != Guid.Empty)
						filterList.Add(new FilterDescriptor(item.property, FilterOperator.IsEqualTo, targetID));
				}
				else if (item.property == "ProjectCode")
				{
					filterList.Add(new FilterDescriptor("Project.ProjectCode", FilterOperator.Contains, item.value));
				}
				else if (item.property == "ApplicationDate_L") //startData - begin
				{
					var targetDate = DateTime.Parse(item.value);
					filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsGreaterThanOrEqualTo, targetDate));
				}
				else if (item.property == "ApplicationDate_H") // startDate - end.
				{
					var targetDate = DateTime.Parse(item.value);
					filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsLessThanOrEqualTo, targetDate));
				}
				else if (item.property == "SignedDate_L") // signedDate - begin.
				{
					var targetDate = DateTime.Parse(item.value);
					filterList.Add(new FilterDescriptor("SignedDate", FilterOperator.IsGreaterThanOrEqualTo, targetDate));
				}
				else if (item.property == "SignedDate_H") // signedDate - end.
				{
					var targetDate = DateTime.Parse(item.value);
					filterList.Add(new FilterDescriptor("SignedDate", FilterOperator.IsLessThanOrEqualTo, targetDate));
				}
				else //other filter.
					filterList.Add(new FilterDescriptor(item.property, FilterOperator.Contains, item.value));
			}
			return filterList;
		}

		private static List<SortDescriptor> GetSortDescriptorFromQueryModel(IEnumerable<JosnQuerySortModel> sortModels)
		{
			//convert the sort description.
			var sortList = new List<SortDescriptor>();
			foreach (var item in sortModels)
			{
				var descriptor = new SortDescriptor()
				{
					Member = item.property,
					SortDirection =
						item.direction.ToLower() == "desc"
							? ListSortDirection.Descending
							: ListSortDirection.Ascending
				};

				if (descriptor.Member == "Organization")
					descriptor.Member = "Organization.OrganizationName";
				else if (descriptor.Member == "ProjectName")
					descriptor.Member = "Project.ProjectName";
				else if (descriptor.Member == "ProjectCode")
					descriptor.Member = "Project.ProjectCode";
				else if (descriptor.Member == "Construction")
					descriptor.Member = "Construction.ConstructionName";
				else if (descriptor.Member == "Unit")
					descriptor.Member = "Construction.Unit";

				sortList.Add(descriptor);
			}
			return sortList;
		}

		internal static void ExecuteSign(Guid[] quantities, bool passed)
		{
			if (null != quantities && quantities.Length > 0)
			{
				using (var context = new SausageEntities())
				{
					var list = context.ProjectQuantity.Where(item => quantities.Contains(item.QuantityID)).ToList();

					foreach (var projectQuantity in list)
					{
						projectQuantity.Signer = Helper.CurrentPrincipal.User.UserName;
						projectQuantity.SignedDate = DateTime.Now;
						projectQuantity.State = passed
													 ? (int)ProjectDataStateEnum.Signed
													 : (int)ProjectDataStateEnum.SignRejected;
					}
					context.SaveChanges();
				}
			}
		}
	}
}